/**
* 本程序用于演示按键控制的逻辑实现， 当按键按下是电源指示灯闪烁3次，并向串口发送文本命令
*
*/

// 无任何操作
#define CMD_NONE 0
// 妇洗
#define CMD_FRONT 1
// 洗便
#define CMD_REAR 2
// 服务
#define CMD_SERVE 3
// 烘干
#define CMD_DRY 4
// 移动
#define CMD_MOVE 5
// 冲水
#define CMD_FLUSH 6

#ifndef DEBUG
#define DEBUG true
#endif
// 按键1停止 Stop
#define STOP_KEY_PIN 22
// 按键2妇洗 Front
#define FRONT_KEY_PIN 24
// 按键3洗便 Rear
#define REAR_KEY_PIN 26
// 按键4服务 Serve
#define SERVE_KEY_PIN 28
// 按键5烘干 Dry
#define DRY_KEY_PIN 30
// 按键6移动 Move
#define MOVE_KEY_PIN 32
// 按键7冲水 Flush
#define FLUSH_KEY_PIN 34
// LED 坐下 SEAT
#define SEAT_LED_PIN 36
// LED 电源 POWER
#define POWER_LED_PIN 38
// 临时命令
int tempCmd = CMD_NONE;
// 命令
int cmd;
// 命令版本号
int cmdVersion;

/**
* 初始化按键定义
*/
void initKeys(){
  // 按键1停止 Stop
  pinMode(STOP_KEY_PIN, INPUT_PULLUP);
  // 按键2妇洗 Front
  pinMode(FRONT_KEY_PIN, INPUT_PULLUP);
  // 按键3洗便 Rear
  pinMode(REAR_KEY_PIN, INPUT_PULLUP);
  // 按键4服务 Serve
  pinMode(SERVE_KEY_PIN, INPUT_PULLUP);
  // 按键5烘干 Dry
  pinMode(DRY_KEY_PIN, INPUT_PULLUP);
  // 按键6移动 Move
  pinMode(MOVE_KEY_PIN, INPUT_PULLUP);
  // 按键7冲水 Flush
  pinMode(FLUSH_KEY_PIN, INPUT_PULLUP);
  // LED 坐下 SEAT
  pinMode(SEAT_LED_PIN, OUTPUT);
 // LED 电源 POWER
  pinMode(POWER_LED_PIN, OUTPUT);
}

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  // 初始化按键控制脚
  initKeys();
  digitalWrite(SEAT_LED_PIN, LOW);
  digitalWrite(POWER_LED_PIN, HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
  // 1.从服务器获取指令,或者从按键获取命令并存放到tempCmd变量中，返回版本号（当前的毫秒数）
  long newCmdVersion = getCmd();  
  // 2.如果新命令版本高于本地的指令版本，则更新指令，否则继续执行上一次的命令
  if (newCmdVersion > cmdVersion) {
    // 更新命令
    cmd = tempCmd;
  }
}

/*
  获取命令
*/
long getCmd() {
  // TODO 将从服务器获取的命令解析存放到全局变量
  // 如果按下STOP按键则清除当前命令
  int newVersion = scanKey(STOP_KEY_PIN, CMD_NONE);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Stop button");
    return newVersion;
  }
  
  // 如果按下妇洗按键则进行洗便操作
  newVersion = scanKey(FRONT_KEY_PIN, CMD_FRONT);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Front button");
    return newVersion;
  }

  // 如果按下洗便按键则进行洗便操作
  newVersion = scanKey(REAR_KEY_PIN, CMD_REAR);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Rear button");
    return newVersion;
  }
 // 如果按下服务按键则进行烘干操作
  newVersion = scanKey(SERVE_KEY_PIN, CMD_SERVE);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Serve button");
    return newVersion;
  }
  // 如果按下烘干按键则进行烘干操作
  newVersion = scanKey(DRY_KEY_PIN, CMD_DRY);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Dry button");
    return newVersion;
  }
  // 如果按下移动按键则进行烘干操作
  newVersion = scanKey(MOVE_KEY_PIN, CMD_MOVE);
  if(newVersion > cmdVersion){
    // 闪烁电源指示灯
    blinkPowerLed();
    log("click Move button");
    return newVersion;
  }
  // 如果按下冲水按键则进行烘干操作
  newVersion = scanKey(FLUSH_KEY_PIN, CMD_FLUSH);
  if(newVersion > cmdVersion){
   // 闪烁电源指示灯
    blinkPowerLed();
    log("click Flush button");
    return newVersion;
  }
  return newVersion;
}
/**
* 扫描按键
*/
int scanKey(int key, int cmd){
  if(digitalRead(key) == LOW){
    delay(20);
    if(digitalRead(key) == LOW){
      // 如果stop按键按下，高电平则清空命令
      tempCmd = cmd;
      while(digitalRead(key) == LOW);
      return cmdVersion + 1;
    }
  }
  return cmdVersion;
}
/**
* 电源指示灯闪烁
*/
void blinkPowerLed(){
    int value = digitalRead(POWER_LED_PIN);
    for(int i=0; i < 6; i++){
      digitalWrite(POWER_LED_PIN, i%2 == 0 ? LOW : HIGH);
      delay(250);
    }
    digitalWrite(POWER_LED_PIN, value);
}
/**
* 打印日志
*/
void log(String log){
  if(DEBUG){
    Serial.println(log);
  }
}